using System.IO;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
using UnityEditor;

/// <summary>
/// 
/// </summary>
public class XEditorBuildAttachmentTab : XEditorAvatarTab
{
    private Texture2D refreshTexture;

    /// <summary>
    /// 
    /// </summary>
    [System.Serializable]
    internal class XAttachmentTabConfigure
    {
        internal string inPath;
        internal string outPath;
        internal List<string> onToggles;
    }

    /// <summary>
    /// 
    /// </summary>
    [SerializeField]
    private XAttachmentTabConfigure configure;

    /// <summary>
    /// 
    /// </summary>
    private List<XEditorToggleProperty> attachmentToggles = new List<XEditorToggleProperty>();

    /// <summary>
    /// 
    /// </summary>
    /// <param name="window"></param>
    public XEditorBuildAttachmentTab(EditorWindow window)
    {
        attachmentToggles = new List<XEditorToggleProperty>();
        configure = new XAttachmentTabConfigure();
        configure.onToggles = new List<string>();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="rect"></param>
    public void OnEnable(Rect rect)
    {
        string dataPath = XEditorUtils.MakeLibraryPath(typeof(XAttachmentTabConfigure).Name);
        if (File.Exists(dataPath))
        {
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(dataPath, FileMode.Open);
            var data = bf.Deserialize(file) as XAttachmentTabConfigure;
            if (data != null)
                configure = data;

            file.Close();
        }

        if (!string.IsNullOrEmpty(configure.inPath))
            OnPathChanged();

        AssetDatabase.Refresh();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    private bool GenerateAttachmentPrefabs()
    {
        List<string> aryFbxs = XEditorUtils.FindFolder(configure.inPath, true, "*.fbx");
        if (aryFbxs.Count < 0)
            return false;

        List<string> aryMats = XEditorUtils.FindFolder(configure.inPath, true, "*.mat");
        foreach (string fbx in aryFbxs)
        {
            GameObject assetGo = AssetDatabase.LoadAssetAtPath<GameObject>(fbx);
            if (!assetGo)
                continue;
            
            string fbxName = Path.GetFileNameWithoutExtension(fbx).ToLower();
            foreach (string mat in aryMats)
            {
                string matName = Path.GetFileNameWithoutExtension(mat).ToLower();
                if (matName.Contains(fbxName))
                {
                    string outPrefabPath = Path.Combine(Application.dataPath, Path.Combine(configure.inPath, XDirectory.Prefabs.ToString()));
                    if (!File.Exists(outPrefabPath))
                    {
                        GameObject prefabGo = new GameObject(matName);
                        if (prefabGo)
                        {
                            GameObject attachmentGo = GameObject.Instantiate(assetGo);
                            attachmentGo.transform.SetParent(prefabGo.transform, false);
                            attachmentGo.transform.localPosition = Vector3.zero;
                            attachmentGo.transform.localScale = Vector3.one;
                            attachmentGo.transform.localEulerAngles = Vector3.zero;
                            attachmentGo.name = matName;

                            MeshRenderer meshRender = attachmentGo.GetComponent<MeshRenderer>();
                            meshRender.materials = new List<Material>() {
                                AssetDatabase.LoadAssetAtPath<Material>(mat)
                            }.ToArray();

                            GeneratePrefab(prefabGo, outPrefabPath, matName);
                        }
                    }
                }
            }
        }

        AssetDatabase.Refresh();
     
        return true;
    }

    /// <summary>
    /// 
    /// </summary>
    private void OnPathChanged()
    {
        List<string> aryFiles = XEditorUtils.FindFolder(configure.inPath);
        if (aryFiles.Count > 0)
        {
            attachmentToggles = new List<XEditorToggleProperty>();
            foreach (string file in aryFiles)
            {
                attachmentToggles.Add(
                    new XEditorToggleProperty(true, file.Replace("\\", "/"), "", configure.onToggles)
                    );
            }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public void OnDisable()
    {
        string dataPath = XEditorUtils.MakeLibraryPath(typeof(XAttachmentTabConfigure).Name);

        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(dataPath);

        bf.Serialize(file, configure);
        file.Close();
    }

    /// <summary>
    /// 
    /// </summary>
    private void OnAttachmentPathGUI()
    {
        XEditorHelper.DrawTitle(typeof(XAttachmentTabConfigure).Name);
        XEditorHelper.BeginContents();

        EditorGUILayout.BeginHorizontal();
        configure.inPath = EditorGUILayout.TextField(typeof(Path).Name, configure.inPath);
        if (GUILayout.Button("...", GUILayout.Width(20)))
        {
            string newPath = EditorUtility.OpenFolderPanel(XDirectory.Prefab.ToString(), string.Empty, string.Empty);
            if (!string.IsNullOrEmpty(newPath))
            {
                newPath = newPath.Replace(Application.dataPath + "/", "");
                if (newPath != configure.inPath)
                {
                    configure.inPath = newPath;
                    OnPathChanged();
                }
            }
        }

        if (GUILayout.Button(refreshTexture, GUILayout.Width(20)))
        {
            GenerateAttachmentPrefabs();
            OnPathChanged();
        }

        EditorGUILayout.EndHorizontal();
        XEditorHelper.EndContents();
    }

    /// <summary>
    /// 
    /// </summary>
    void OnAttachmentPrefabGUI()
    {
        if (XEditorHelper.DrawHeader(XDirectory.Prefabs.ToString()))
        {
            XEditorHelper.BeginContents();
            for (int idx = 0; idx < attachmentToggles.Count; idx++)
            {
                bool state = GUILayout.Toggle(attachmentToggles[idx].state, Path.GetFileName(attachmentToggles[idx].content.text));
                if (state != attachmentToggles[idx].state)
                {
                    attachmentToggles[idx].state = state;
                }
            }

            GUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("Build", GUILayout.MaxWidth(75f)))
                BuildAttachment();
            if (GUILayout.Button("Reset", GUILayout.MaxWidth(75f)))
                BuildReset();
            GUILayout.EndHorizontal();

            EditorGUILayout.Space();
            XEditorHelper.EndContents();
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="rect"></param>
    public void OnGUI(Rect rect)
    {
        if (!refreshTexture)
            refreshTexture = EditorGUIUtility.FindTexture("Refresh");

        OnAttachmentPathGUI();
        OnAttachmentPrefabGUI();
    }

    /// <summary>
    /// 
    /// </summary>
    public void OnReload()
    {

    }

    /// <summary>
    /// 
    /// </summary>
    public void BuildAttachment()
    {
        for (int idx = 0; idx < attachmentToggles.Count; idx++)
        {
            if (attachmentToggles[idx].state)
            {
                GenerateAttachment(attachmentToggles[idx].content.text, configure.outPath);
            }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="fbxAssetPath"></param>
    /// <param name="outDir"></param>
    /// <returns></returns>
    public bool GenerateAttachment(string fbxAssetPath, string outDir)
    {
        GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(fbxAssetPath);
        if (!prefab)
            throw new System.NullReferenceException();

        if (string.IsNullOrEmpty(outDir))
        {
            outDir = Path.GetDirectoryName(fbxAssetPath).Replace(XDirectory.Art.ToString(), XDirectory.Resources.ToString());
        }
        Debug.LogError(outDir);
        if (!Directory.Exists(outDir))
            Directory.CreateDirectory(outDir);

        string elementPath = Path.Combine(outDir, XDirectory.Element.ToString().ToLower());
        if (!Directory.Exists(elementPath))
            Directory.CreateDirectory(elementPath);

        string prefabPath = Path.Combine(outDir, XDirectory.Prefab.ToString().ToLower());
        if (!Directory.Exists(prefabPath))
            Directory.CreateDirectory(prefabPath);

        XAvatarAttachElement element = ScriptableObject.CreateInstance<XAvatarAttachElement>();
        if (element)
        {
            element.Name = prefab.name;

            GameObject obj = GameObject.Instantiate(prefab);
            Object elementPrefab = GeneratePrefab(obj, prefabPath, prefab.name);
            element.Prefab = elementPrefab;
            element.PrefbPath = prefabPath + "/" + prefab.name;

            string outElementConfigFullPath = Path.Combine(elementPath,
                string.Format("{0}.{1}", prefab.name, "asset"));

            GenerateAsset(outElementConfigFullPath, element);
        }

        return true;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="go"></param>
    /// <param name="path"></param>
    /// <param name="name"></param>
    /// <returns></returns>
    Object GeneratePrefab(GameObject go, string path, string name)
    {
        string fullpath = path + "/" + name + ".prefab";

        GameObject prefab = PrefabUtility.SaveAsPrefabAsset(go, fullpath);
        GameObject.DestroyImmediate(go);

        return prefab;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="path"></param>
    /// <param name="asset"></param>
    void GenerateAsset(string path, Object asset)
    {
        AssetDatabase.DeleteAsset(path);
        AssetDatabase.CreateAsset(asset, path);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public XBoneNogType GetNogType(string name)
    {
        for (XBoneNogType nog = XBoneNogType.None; nog < XBoneNogType.All; nog++)
        {
            if (nog.ToString().ToLower() == name.ToLower())
                return nog;
        }

        return XBoneNogType.None;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    public XAttachDimension GetDimenssion(string name)
    {
        for (XAttachDimension nog = XAttachDimension.Normal; nog <= XAttachDimension.Middle; nog++)
        {
            if (nog.ToString().ToLower() == name.ToLower())
                return nog;
        }

        return XAttachDimension.Normal;
    }

    /// <summary>
    /// 
    /// </summary>
    public void BuildReset()
    {

    }
}